package com.ellison.springdemo.springbase.aop;

import com.ellison.springdemo.annotation.ReturnValue;
import com.ellison.springdemo.annotation.TargetMethod;
import com.ellison.springdemo.annotation.ThrowsAnno;
import com.ellison.springdemo.common.service.DataCheck;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;

import java.io.PrintWriter;
import java.io.StringWriter;
import java.util.ArrayList;
import java.util.List;

/**
 * @author ellisonpei
 */

@Component
@Aspect
public class AopAnnotation {

    /**
     * introduction 引介动态添加功能，并且改变目标类的类型，其实就是目标类多实现了接口而已
     */
    @DeclareParents(value = "com.ellison.springdemo.common.service.impl.BankServiceImpl",
            defaultImpl = com.ellison.springdemo.common.service.impl.DataCheckImpl.class)
    private DataCheck dataCheck;

    /**
     * 这一类的 叫切点
     * 切点（Pointcut） == 连接点的集合
     */
    @Pointcut(value = "execution(public * com.ellison.springdemo.common.service.*.*(..))")
    public void serviceAdvice() {
    }

    @Pointcut(value = "execution(public * com.ellison.springdemo.common.service.*.method1(..))")
    public void method1() {
    }

    @Pointcut(value = "execution(public * com.ellison.springdemo.common.service.StudentService.method2(..))")
    public void method2() {
    }

    @Pointcut(value = "execution(public * com.ellison.springdemo.common.service.BankService.queryBank(..))")
    public void queryBank(){}

    // 在实体类上的切点 是不生效的
    //@Pointcut(value = "execution(public * com.ellison.springdemo.entity.User.getAddress(..))")
    //public void entityPointCut(){}
    //
    //@Before(value = "entityPointCut()")
    //public void entityPoint(JoinPoint joinPoint){
    //    Object[] args = joinPoint.getArgs();
    //    System.out.println("=================调用User.getAddress()===================前置增强====================");
    //}

    @Before("serviceAdvice()")
    public void advice1(JoinPoint joinPoint) {
        Signature signature = joinPoint.getSignature();
        Object[] args = joinPoint.getArgs();
//        System.out.println("前置增强");
    }

    /**
     * 这个方法就是一个 advisor（通知） 是一个切面
     * <p>
     * 除去 @Around 注解  这个方法叫 advice  ，也叫增强。增强（Advice） == 具体增强的代码逻辑
     *
     * @param proceedingJoinPoint 连接点（JoinPoint） == 一个连接点就对应着一个被代理方法
     * @return String
     * @throws Throwable
     */
    @Around("method1()")
    public String advice(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
        System.out.println("前置通知");
        Object proceed = proceedingJoinPoint.proceed();
        System.out.println("后置通知");
        return proceed.toString();

    }

    @After(value = "method2()")
    public void advice2(JoinPoint joinPoint) {
        Signature signature = joinPoint.getSignature();
        Object[] args = joinPoint.getArgs();
        List<String> argList = new ArrayList<String>();
        for (Object arg : args) {
            argList.add(arg.toString());
        }
        System.out.println("后置增强处理" + argList);
    }

    /**
     * 拦截注解
     * @param joinPoint
     * @param targetMethod
     */
    @Before(value = "@annotation(targetMethod)", argNames = "joinPoint,targetMethod")
    public void xx(JoinPoint joinPoint, TargetMethod targetMethod) {
        System.out.println("===============注解拦截 前置通知=========");
        System.out.println("==================targetMethod.name = " + targetMethod.name());
    }

    @AfterReturning(value = "@annotation(returnValue)", returning = "retVal")
    public void afterReturning(JoinPoint joinPoint, ReturnValue returnValue, Object retVal) {

        System.out.println("==============AspectAnnotation 后置通知  拿返回值=========" + retVal);
    }

    @AfterThrowing(value = "@annotation(throwsAnno)", throwing = "e")
    public void throwMethod(JoinPoint joinPoint, ThrowsAnno throwsAnno, Throwable e) {
        // java输出异常栈
        StringWriter stringWriter = new StringWriter();
        e.printStackTrace(new PrintWriter(stringWriter, true));
        String message = stringWriter.getBuffer().toString();

        System.out.println("==============AspectAnnotation 异常通知  拿异常=========" + message);
    }

    //@Before("queryBank() && args(bankId,id,list)")
    //public void before2(String bankId, Integer id, List list) {
    //    System.out.println("===============service1包的拦截=========");
    //}
}
